package com.tju.resource.tool.tool;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * @Author HyEISN
 */
public class QuickQuery {

    public enum QueryType {
        EQUALS("EQUALS"),
        LIKE("LIKE");

        private String type;

        QueryType(String type) {
            this.type = type;
        }
    }

    /**
     * Query mode equal.
     */
    public static final String EQUALS = "EQUALS";

    /**
     * Query mode like.
     */
    public static final String LIKE = "LIKE";

    @Data
    static class QueryParam {
        private QueryType queryType;
        private String column;
        private Object value;

        public QueryParam(QueryType queryType, String column, Object value) {
            this.queryType = queryType;
            this.column = column;
            this.value = value;
        }
    }

    /**
     * Return link params, example: QuickQuery.params().putOnce("name", "Mike")
     */
    public static JSONObject params() {
        return JSONUtil.parseObj("{}");
    }

    /**
     * Return link params, example: QuickQuery.params("column", value)
     */
    public static JSONObject params(String column, Object value) {
        JSONObject obj = JSONUtil.parseObj("{}");

        obj.putOnce(column, value);

        return obj;
    }

    /**
     * set and get param
     */
    public static Object param(QueryType queryType, String column, Object value) {
        return new QueryParam(queryType, column, value);
    }

    /**
     * Return query record list.
     *
     * @param mapper model mapper
     * @param params query params, just like json string: QuickQuery.params().putOnce("name", "asd").putOnce("age", 99)
     */
    public static <T> List<T> list(BaseMapper<T> mapper, JSONObject params) {
        QueryWrapper<T> query = new QueryWrapper<>();

        params.forEach(query::eq);

        return mapper.selectList(query);
    }

    public static <T> List<T> list(BaseMapper<T> mapper, String column, Object... in) {
        QueryWrapper<T> query = new QueryWrapper<>();

        query.in(column, in);

        return mapper.selectList(query);
    }

    /**
     * Return query record list.
     *
     * @param mapper  model mapper
     * @param params  query params, just like json string: QuickQuery.params().putOnce("name", "asd").putOnce("age", 99)
     * @param orderBy order by column
     * @param desc    order by column and desc sort
     */
    public static <T> List<T> list(BaseMapper<T> mapper, JSONObject params, String orderBy, boolean desc) {
        QueryWrapper<T> query = new QueryWrapper<>();

        params.forEach(query::eq);
        if (desc) {
            query.orderByDesc(orderBy);
        } else {
            query.orderByAsc(orderBy);
        }

        return mapper.selectList(query);
    }

    /**
     * Customer query type, like or equals.
     *
     * @param params example: QuickQuery.params().putOnce("name", "asd," + QuickQuery.LIKE).putOnce("age", 99 + "," + QuickQuery.EQUALS)
     */
    @Deprecated
    public static <T> List<T> custom(BaseMapper<T> mapper, JSONObject params) {
        QueryWrapper<T> query = new QueryWrapper<>();

        params.forEach((k, v) -> {
            String values[] = v.toString().split(",");

            if (StringUtils.equals(values[1], EQUALS)) {
                query.eq(k, values[0]);
            } else if (StringUtils.equals(values[1], LIKE)) {
                query.like(k, values[0]);
            }
        });

        return mapper.selectList(query);
    }

    /**
     * query data by page limit
     *
     * @param mapper
     * @param page current page
     * @param limit rows
     * @param params query params
     */
    public static <T> IPage<T> page(BaseMapper<T> mapper, int page, int limit, Object... params) {
        QueryWrapper<T> query = new QueryWrapper<>();
        IPage<T> iPage = new Page<>(page, limit);

        for (Object param : params) {
            QueryParam qm = (QueryParam) param;

            if (qm.queryType.equals(QueryType.EQUALS)) {
                if (!StringUtils.isBlank(qm.getValue() + "")) {
                    query.eq(qm.getColumn(), qm.getValue());
                }
            }

            if (qm.queryType.equals(QueryType.LIKE)) {
                if (!StringUtils.isBlank(qm.getValue() + "")) {
                    query.like(qm.getColumn(), qm.getValue());
                }
            }
        }

        return mapper.selectPage(iPage, query);
    }

    /**
     * Query one result by one condition
     */
    public static <T> T byOne(BaseMapper<T> mapper, String column, Object value) {
        List<T> list = list(mapper, params().putOnce(column, value));

        return list.size() != 0 ? list.get(0) : null;
    }

    /**
     * Get eq query
     */
    public static <T> QueryWrapper<T> wrapper(BaseMapper<T> mapper, String column, Object value) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq(column, value);

        return queryWrapper;
    }

    /**
     * Get in query
     */
    public static <T> QueryWrapper<T> wrapper(BaseMapper<T> mapper, String column, Object[] in) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();

        queryWrapper.in(column, in);

        return queryWrapper;
    }

    /**
     * Get multi column eq query, using reference <code>list(BaseMapper<T> mapper, JSONObject params)</code>
     */
    public static <T> QueryWrapper<T> wrapper(BaseMapper<T> mapper, JSONObject params) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();

        params.forEach(queryWrapper::eq);

        return queryWrapper;
    }

}
